#include <string>
#include <iostream>
#include "CTPServer.h"
#include "FABase/thread.h"
#ifdef WIN32
#else
#include <signal.h>
#include <sys/file.h>
#include <pthread.h>
#endif

using namespace std;

//quote
typedef IFAQuote* (*YCreateObject)(IQuoteEvent*pEvent);
typedef int (*YReleaseObject)(IFAQuote *pQuote);
//sock
typedef IServer*(*YSockServerCreateObject)(int port, IP_ADDRESS ipAddress, IServerHandle * pHandle);
typedef void (*YSockServerRun)();
//redis
typedef  IRedis* (*YKRedisCreateObject)(IRedisHandle*pHandle);
typedef  void (*YKRedisReleaseObject)();
//mysql
typedef  IMysql* (*YKMysqlCreateObject)(IMysqlHandle*pHandle);
typedef  void (*YKMysqlReleaseObject)();

#ifdef WIN32
#define QUOTE_SO ("FAQuote.dll")
#define SOCKSVR_SO ("FASockServer.dll")
#define REDIS_SO ("FARedis.dll")
#define MYSQL_SO ("FAMysql.dll")
#else
#define QUOTE_SO ("FAQuote.so")
#define SOCKSVR_SO ("FASockServer.so")
#define REDIS_SO ("FARedis.so")
#define MYSQL_SO ("FAMysql.so")
#endif

#define CREATE_API ("CreateObject")
#define RELEASE_API ("ReleaseObject")
#define RUN_API ("Run")


IFAQuote * _pQuote = NULL;
CYKQuote * _pYKQuote = new CYKQuote();
IRedis	* _pYKRedis = NULL;
IMysql	* _pYKMysql= NULL;
IServer *_pSockServer = NULL;
YKSock * pSock = new YKSock();
CYKSemaphore *_pSema = new CYKSemaphore;

CYKRedisHandle * _pRedisHandle = new CYKRedisHandle;
CYKMysqlHandle * _pMysqlHandle = new CYKMysqlHandle;

YReleaseObject _funcQuoteRelease = 0;
YCreateObject _funcQuoteCreate = 0;
YSockServerCreateObject _funcSockServer = 0;
YSockServerRun _funcSockRun = 0;
YKRedisCreateObject _funcRedisCreate = 0;
YKRedisReleaseObject _funcRedisRelease = 0;
YKMysqlCreateObject _funcMysqlCreate = 0;
YKMysqlReleaseObject _funcMysqlRelease = 0;

CDllHelper dll_quote(QUOTE_SO);
CDllHelper dll_socksvr(SOCKSVR_SO);
CDllHelper dll_mysql(MYSQL_SO);
CDllHelper dll_redis(REDIS_SO);

#ifndef WIN32
void InitDaemon(int8_t nochdir, int8_t noclose)
{
	daemon(nochdir, noclose);

	//ignore signals
	signal(SIGINT, SIG_IGN);
	signal(SIGHUP, SIG_IGN);
	signal(SIGQUIT, SIG_IGN);
	signal(SIGPIPE, SIG_IGN);
	signal(SIGTTOU, SIG_IGN);
	signal(SIGTTIN, SIG_IGN);
	signal(SIGTERM, SIG_IGN);
}
#endif

void *QuoteThread(const bool*bStop,void*param)
{

	_funcQuoteCreate = dll_quote.GetProcedure<YCreateObject>(CREATE_API);
	_funcQuoteRelease = dll_quote.GetProcedure<YReleaseObject>(RELEASE_API);
	printf("wait for init\n");
	//load so
	if (!_funcQuoteCreate)
	{
		printf("[%s]libQuote open fail\n",__FUNCTION__);
		return 0;
	}

	_pQuote = _funcQuoteCreate(_pYKQuote);
	if (!_pQuote)
	{
		printf("%s,%d\n", __FUNCTION__, __LINE__);
		return 0;
	}

	printf("wait for connect\n");

	if (SUCCESS != _pQuote->Connect(URL_QUOTE))
	{
		printf("%s,%d\n", __FUNCTION__, __LINE__);
		return 0;
	}

	_pSema->wait(INFINITE);
	
	return 0;
}

int Release()
{
	/*
	release
	*/

	if (!_funcQuoteRelease)
	{
		printf("[%s]Quote open fail\n",__FUNCTION__);
		return 0;
	}
	_funcQuoteRelease(_pQuote);

	if (_pYKQuote)
	{
		delete _pYKQuote;
		_pYKQuote = NULL;
	}

	printf("finish release\n");
	return 0;
}

void *SockThread(const bool*bStop,void*param)
{
	_funcSockServer = dll_socksvr.GetProcedure<YSockServerCreateObject>(CREATE_API);
	if(!_funcSockServer)
		return 0;
	_funcSockRun = dll_socksvr.GetProcedure<YSockServerRun>(RUN_API);	
	if(!_funcSockRun)
		return 0;
	_pSockServer = _funcSockServer(9999, IPV4, pSock);
	_funcSockRun();
	return 0;
}

void *RedisThread(const bool*bStop,void*param)
{
	_funcRedisCreate = dll_redis.GetProcedure<YKRedisCreateObject>(CREATE_API);
	if(!_funcRedisCreate)
		return 0;
	_funcRedisRelease= dll_redis.GetProcedure<YKRedisReleaseObject>(RELEASE_API);
	if(!_funcRedisRelease)
		return 0;
	_pYKRedis = _funcRedisCreate(_pRedisHandle);
	_pYKRedis->Start();
	return 0;
}

void *MysqlThread(const bool*bStop,void*param)
{
	_funcMysqlCreate = dll_mysql.GetProcedure<YKMysqlCreateObject>(CREATE_API);
	if(!_funcMysqlCreate)
		return 0;
	_funcMysqlRelease= dll_mysql.GetProcedure<YKMysqlReleaseObject>(RELEASE_API);
	if(!_funcMysqlRelease)
		return 0;
	_pYKMysql = _funcMysqlCreate(_pMysqlHandle);
	_pYKMysql->Start();
	return 0;
}

int main(int argc, char *argv[])
{
	InitSocket();

#ifndef WIN32
	bool is_daemon = false;

	if (argc > 1)
	{
		if (0 == strcasecmp(argv[1], "-d"))
		{
			is_daemon = true;
		}
	}

	int lock_fd = open((const char *)argv[0], O_RDONLY);
	if (lock_fd < 0)
	{
		exit(1);
	}

	if (flock(lock_fd, LOCK_EX | LOCK_NB) < 0)
	{
		printf("Catalog Server was lauched!\n");
		exit(1);
	}

	if (is_daemon)
	{
		InitDaemon(1, 0);
	}
#endif
	int input_x = 0;

#ifdef _DEBUG
	//printf("[DEBUG]if you want debug,you can attach the thread,then input any word;else not.\n");
	//cin>>input_x;
#endif

	//Init Sock
	CYKThread _th2(SockThread);
	_th2.start();
	
	//Init Redis
	CYKThread _th3(RedisThread);
	_th3.start();

	//Init Mysql
	CYKThread _th4(MysqlThread);
	_th4.start();

	//Init Quote
	CYKThread _th1(QuoteThread);
	_th1.start();
	

	printf("input any key to release\n");
	cin>>input_x;
	cin>>input_x;
	Release();
	return 0;
}